//	Copyright (c) 2008, x-port.net ltd.
//
//	All rights reserved.
//
//	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
//	    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//	    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//	    * Neither the name of the x-port.net ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
//	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//	A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//	CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#include "stdafx.h"
#include "anyelementwithxbl.h"

#include <DOM/HTMLDOMTranslator/HTMLDOMTranslator.h>
#include "UIImplRepository.h"
#include "XFormsXFormsElement.h"


#include "XFormsApp.h"
extern CXFormsApp theApp;

CAnyElementWithXBL::CAnyElementWithXBL(void)
	:m_pForm(0)
{
}

CAnyElementWithXBL::~CAnyElementWithXBL(void)
{
}

STDMETHODIMP CAnyElementWithXBL::Detach()
{
	HRESULT hr = __super::Detach();
	try
	{
		if(m_pEngine)
			m_pEngine->Detach();
		m_pEngine.Release();
	}
	catch(...)
	{
		::AtlTrace("\n!!formsPlayer.dll: Error detaching and releasing XBLEngine from CAnyElementWithXBL\n");
	}
	return hr;
}

//At DocumentReady, fetch a UI Engine and attach it.
HRESULT CAnyElementWithXBL::DocumentReady()
{
	HRESULT hr = __super::DocumentReady();
	hr = getUI(&m_pEngine);
	if(m_pEngine)
	{
		CComQIPtr<IEngine2> pEngine2 = m_pEngine;
	/*
		//This doesn't work:  IE doesn't actually import the namespaces until this 
		// function has returned, so when the Attach occurs, no additional namespace
		// prefixes are used in resolving behaviours for new nodes.

		if(pEngine2)
		{
			CComPtr<IXMLDOMNodeList> pNl;
			pEngine2->get_activeNamespaces(&pNl);
			m_pFormControl->m_pXForms->importAdditionalNamespacePrefixes(pNl);
		}
	*/

		CComPtr<IHTMLElement> pEl;
		hr = GetMasterElement(&pEl);
		if(pEl)
		{
			CComQIPtr<IDispatchEx> pDispEx(pEl);
			hr =m_pEngine->Attach(pDispEx);
		}
	}
	return hr;
}



//<summary>
//	If specified, fetches a locally specified binding from an XML Data Island.
//</summary>
//<returns>
//	S_OK if successful<br />
//	S_FALSE if no xbl-binding was specified<br />
//	otehrwise, an error value.
//</returns>
HRESULT CAnyElementWithXBL::GetLocallySpecifiedBinding(IEngine ** ppEngine)
{
	CComBSTR sId;
	HRESULT hr = GetLocallySpecifiedBindingId(sId);
	if(S_OK == hr && sId)
	{
		CUIImplRepository * pRepository = m_pForm->GetUIImplRepository();
		if(pRepository)
		{
			CComPtr<IXMLDOMDocument> pXMLDocument;
//TEMPDISABLE
//			hr = m_pXForms->GetXMLElementById(sId,&pXMLDocument);
			if(pXMLDocument)
			{
				CComPtr<IXMLDOMNode> pNode;
				pXMLDocument->selectSingleNode(L"*",&pNode);
				if(pNode)
				{
hr = E_FAIL;
					//					hr = pRepository->CreateUIImpl(pNode,ppEngine);	
					if(FAILED(hr))
					{
						CComBSTR bsXML;
						pNode->get_xml(&bsXML);
						::MessageBoxW(0,bsXML,0,0);
					}
				}	
			}
		}
		else
		{
			//hr = FP_E_NOREPOSITORY;
			//::SetupErrorInfo(hr);
		}
	}
	else
	{
		hr = S_FALSE;
	}
	return hr;
}

HRESULT CAnyElementWithXBL::GetLocallySpecifiedBindingId(CComBSTR & bsId)
{
	HRESULT hr = S_FALSE;
	CComQIPtr<IHTMLElement> pMaster = GetControllingUnknown();
	if(pMaster)
	{
		CComVariant vtRetVal;
		CComBSTR bsXBLAttributeName(L"xbl-binding");
		hr = pMaster->getAttribute(bsXBLAttributeName,1,&vtRetVal);
		if(S_OK == hr && VT_BSTR == vtRetVal.vt)
		{
			bsId = vtRetVal.bstrVal;
		}
		else
		{
			hr = S_FALSE;
		}
	}
	return hr;
}

HRESULT CAnyElementWithXBL::getUI(IEngine ** ppEngine)
{
	HRESULT hr = E_FAIL;
	
	//First see if it has an xbl-binding attribute 
	//	which can be used to retrieve a node from an 
	//	xml data island in the master document.
	hr = GetLocallySpecifiedBinding(ppEngine);
	if(S_FALSE == hr)
	{
	
		//Then use the standard transformation method.
		CComPtr<IXMLDOMNode> pNode;
		hr = getXML(&pNode);

		if(pNode) 
		{
			//get the xblEngine
			CUIImplRepository * pRepository = m_pForm->GetUIImplRepository();
			
			try
			{
				hr = pRepository->GetUIImpl(pNode,ppEngine);
				if(!*ppEngine)
				{
					CComBSTR sTagsXML;
					pNode->get_xml(&sTagsXML);
					//ATLTRACE2("'formsplayer.dll': No UI handler loaded for %S\n",sTagsXML);
				}
		
			} 
			catch(...) 
			{
				CComPtr<IErrorInfo> pErr;
				::GetErrorInfo(0,&pErr);
				CComBSTR sDescription;
				if(pErr)
					pErr->GetDescription(&sDescription);
				CString s;
				CComBSTR sTagsXML;
				pNode->get_xml(&sTagsXML);
				s.Format("'formsplayer.dll': error %S in resolving UI for:\n %S\n",sDescription,sTagsXML);
				::MessageBox(0,s,0,0);
			}

		}
	}

	return hr;
}

HRESULT CAnyElementWithXBL::getXML(IXMLDOMNode ** ppXML)
{
	HRESULT hr = E_NOINTERFACE;
	CComQIPtr<IHTMLDOMNode> pMaster(GetControllingUnknown());
	if(pMaster)
	{
		CHTMLDOMTranslator translator(CLSID_DOMDocument60);
		hr = translator.cloneNode(pMaster,ppXML,true);
	}
	return hr;

}


STDMETHODIMP CAnyElementWithXBL::get_formKey(LONG * newVal)
{
	//There is not much point in implementing this function.
	return E_NOTIMPL;
}

STDMETHODIMP CAnyElementWithXBL::put_formKey(LONG newVal)
{
	HRESULT hr = E_ACCESSDENIED;
	if(!m_pForm)
	{
		hr = theApp.FormsManager().GetForm(newVal,&m_pForm);
	}

	return hr;
}
